package TI;

import java.util.ArrayList;
import java.util.List;

import org.junit.Before;
import org.junit.Test;

import Exceptions.BranchOfficeAlreadyExistsException;
import Magnitudes.Pesos;
import Products.Foodstuff;
import Products.Presentation;
import Products.Product;
import junit.framework.TestCase;
import static org.mockito.Mockito.*;

public class SystemoTest extends TestCase {

	Systemo systemToTest;
	BranchOffice aBranchOffice = mock(BranchOffice.class);
	BranchOffice anotherBranchOffice = mock(BranchOffice.class);
	Product foodstuff = mock(Product.class);
	Presentation presentation = mock(Presentation.class);
	Address anAddress = mock(Address.class);
	Address anotherAddress = mock(Address.class);
	Storehouse aStorehouse = mock(Storehouse.class);
	ParticularCustomer customer = mock(ParticularCustomer.class);
	ParticularCustomer anotherCustomer = mock(ParticularCustomer.class);
	Exception exception;
	
	@Before
	public void setUp(){
		systemToTest = new Systemo();
	}

	@Test
	public void testGivenASystemoWithASingleBranchOfficeWhenOpenANewBranchOfficeAtTheBranchOfficeListShouldContentTwoOfThem(){
		
		systemToTest.openANewBranchOfficeAt(anAddress, systemToTest);
		systemToTest.openANewBranchOfficeAt(anotherAddress, systemToTest);
		assertEquals(2, systemToTest.numberOfBranchOffices());
	}
	
	@Test
	public void testGivenAnEmptySystemooooWhenOpenANewBranchOfficeAtTheBranchOfficeListShouldContentJustOne(){
		systemToTest.openANewBranchOfficeAt(anAddress, systemToTest);
		assertEquals(1, systemToTest.numberOfBranchOffices());
	}
	
	@Test
	public void testGivenAnEmptySystemooooWhenOpenANewBranchOfficeAtAnAddressShouldContentAt1AbranchOfficeWithTheGivenAddress(){
		systemToTest.openANewBranchOfficeAt(anAddress, systemToTest);
		assertEquals(anAddress, systemToTest.getBranchOffices().get(0).getAddress());
	}
	
	@Test
	public void testGivenAnEmptySystemooooWhenOpenANewBranchOfficeAtThenGetStorehousesShouldBeEmpty(){
		systemToTest.openANewBranchOfficeAt(anAddress, systemToTest);
		assertTrue(systemToTest.getStorehouses().isEmpty());
	}
	
	
	@Test
	public void testGivenAnEmptySystemooooWhenOpenANewBranchOfficeWithAStorehouseTheBranchOfficeListShouldContentJustOne(){
		systemToTest.openANewBranchOfficeWithAStorehouse(anAddress, systemToTest);
		assertEquals(1, systemToTest.numberOfBranchOffices());
	}

	@Test
	public void testGivenAnEmptySystemooooWhenOpenANewBranchOfficeWithAStorehouseShouldContentAt1AbranchOfficeWithTheGivenAddress(){
		systemToTest.openANewBranchOfficeWithAStorehouse(anAddress, systemToTest);
		assertEquals(anAddress, systemToTest.getBranchOffices().get(0).getAddress());
	}
	
	@Test
	public void testGivenAnEmptySystemooooWhenOpenANewBranchOfficeWithAStorehouseThenGetStorehousesShouldNotBeEmpty(){
		systemToTest.openANewBranchOfficeWithAStorehouse(anAddress, systemToTest);
		assertFalse(systemToTest.getStorehouses().isEmpty());
	}
	

	@Test
	public void testGivenASystemooooWhenAssociateAStorehouseToAnExistentBranchOfficeShouldBeAlwaysPossible(){
		systemToTest.openANewBranchOfficeWithAStorehouse(anAddress, systemToTest);
		BranchOffice branchOffice = systemToTest.getBranchOffices().get(0);
		systemToTest.associateStorehouse(aStorehouse, branchOffice);
		assertTrue(systemToTest.getStorehouses().contains(aStorehouse));
	}
	
	@Test
	public void testGivenASystemooooWithABranchOfficesWhenGetStorehousesShouldReturnAllStorehouses(){
		systemToTest.openANewBranchOfficeWithAStorehouse(anAddress, systemToTest);
		systemToTest.openANewBranchOfficeWithAStorehouse(anotherAddress, systemToTest);
		BranchOffice branchOffice = systemToTest.getBranchOffices().get(1);
		systemToTest.associateStorehouse(aStorehouse, branchOffice);
		assertEquals(3, systemToTest.getStorehouses().size());
	}
	
	@Test
	public void testGivenASystemooooWithABranchOfficesThatShareTheSameStorehouseWhenGetStorehousesShouldReturnAllStorehousesWithoutReps(){
		systemToTest.openANewBranchOfficeAt(anAddress, systemToTest);
		systemToTest.openANewBranchOfficeAt(anotherAddress, systemToTest);
		BranchOffice branchOffice = systemToTest.getBranchOffices().get(0);
		BranchOffice anotherBranchOffice = systemToTest.getBranchOffices().get(1);
		systemToTest.associateStorehouse(aStorehouse, branchOffice);
		systemToTest.associateStorehouse(aStorehouse, anotherBranchOffice);
		assertEquals(2, systemToTest.getStorehouses().size());
	}
	
	@Test
	public void testGivenASystemooooWhenAddACustomerShouldBeRegistered(){
		systemToTest.addCustomer(customer);
		assertTrue(systemToTest.existsClient(customer));
		systemToTest.addCustomer(anotherCustomer);
		assertTrue(systemToTest.existsClient(anotherCustomer));
	}
	
	@Test
	public void testGivenASystemooooWhenAddACustomerThenShouldExists(){
		systemToTest.addCustomer(customer);
		assertTrue(systemToTest.existsClient(customer));
		systemToTest.addCustomer(anotherCustomer);
		assertTrue(systemToTest.existsClient(anotherCustomer));
	}
	
	@Test
	public void testGivenASystemooooWhenTheCustomerIsNotAddedThenShouldNotExists(){
		assertFalse(systemToTest.existsClient(customer));
		assertFalse(systemToTest.existsClient(anotherCustomer));
	}
	
	public void testGivenASystemooooWhenGetAllSalesShouldSendToAllBranchOfficesGetSales(){
		Systemo systemSpy = spy(new Systemo());
		List<BranchOffice> branchOffices = new ArrayList<BranchOffice>();
		branchOffices.add(aBranchOffice);
		branchOffices.add(anotherBranchOffice);
		doReturn(branchOffices).when(systemSpy).getBranchOffices();
		systemSpy.getAllSales();
		verify(aBranchOffice).getSales();
		verify(anotherBranchOffice).getSales();
	}
	
	@Test
	public void testGivenASystemooooWithoutProductsWhenAddProductSouldHaveOneProduct(){
		systemToTest.addNewProduct(foodstuff);
		assertTrue(systemToTest.getProducts().contains(foodstuff));
	}
	
	@Test
	public void testGivenASystemooooWhenBuyAProductForABranchOfficeThisBranchOfficeShouldReceiveTheMessageReceivePresentations(){
		Systemo systemSpy = spy(new Systemo());
		List<BranchOffice> branchOffices = new ArrayList<BranchOffice>();
		branchOffices.add(aBranchOffice);
		Pesos fifty = new Pesos(50);
		systemSpy.buyAProduct(presentation, 10, fifty, aBranchOffice);
		verify(aBranchOffice).receivePresentations(presentation, 10, fifty);
		// Tiene que updetear el precio en todos los branchoffices tambien!!! 
	}
	
	@Test
	public void testGivenASystemooooWhenGetCashInBranchShouldSendgetCashToTheGivenBranch(){
		Systemo systemSpy = spy(new Systemo());
		systemSpy.getCashInBranch(aBranchOffice);
		verify(aBranchOffice).getCash();
	}
	
	@Test
	public void testGivenASystemooooWhenGetCashInAllBranchesShouldSendgetCashToAllBranches(){
		Systemo systemSpy = spy(new Systemo());
		List<BranchOffice> branchOffices = new ArrayList<BranchOffice>();
		branchOffices.add(aBranchOffice);
		branchOffices.add(anotherBranchOffice);
		when(systemSpy.getBranchOffices()).thenReturn(branchOffices);
		when(aBranchOffice.getCash()).thenReturn(new Pesos(10));
		when(anotherBranchOffice.getCash()).thenReturn(new Pesos(10));
		systemSpy.getCashInAllBranches();
		verify(aBranchOffice).getCash();
		verify(anotherBranchOffice).getCash();
	}
	
	// Falta desde modify...() (ver si hace falta), sentMail..() y los getReport...();
}
